package cc.rengu.igas.mcps.core.service.trans.common;

import cc.rengu.igas.mcps.common.constant.McpsParamConstant;
import cc.rengu.igas.mcps.common.dao.TermKeyMapper;
import cc.rengu.igas.mcps.common.dao.impl.TermKeyMapperImpl;
import cc.rengu.igas.mcps.common.entity.TermKey;
import cc.rengu.igas.mcps.common.enums.KeyTypeEnum;
import cc.rengu.igas.mcps.common.enums.RespCodeEnum;
import cc.rengu.igas.mcps.core.service.base.ManageService;
import cc.rengu.igas.mcps.facade.bean.TermWorkKeyInfo;
import cc.rengu.igas.mcps.facade.request.PosSignInRequest;
import cc.rengu.igas.mcps.facade.response.PosSignInResponse;
import cc.rengu.igas.share.core.model.MchntTermInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.oltp.service.common.constant.AppConfigConstant;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.entity.SysParam;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * POS终端签到 M00MC001
 */
public class TermSignInService extends ManageService {
    /*设置全局变量*/
    @Override
    protected Object bizBeforeCust() throws Exception {
        PosSignInRequest posSignInRequest = new PosSignInRequest();
        ConvertUtil.convertOutput(posSignInRequest);
        return posSignInRequest;
    }

    @Override
    protected BizResponse bizProcessCust(Object request) throws Exception {
        PosSignInRequest posSignInRequest = (PosSignInRequest) request;
        BizResponse bizResponse = new BizResponse();
        String instId = posSignInRequest.getHeader().getInstId();
        String mchntNo = posSignInRequest.getMchntNo();
        String termNo = posSignInRequest.getTermNo();
        /* 获取终端信息 */
        MchntService mchntService = new MchntServiceImpl();
        MchntTermInfo mchntTermInfo = mchntService.getMchntTermInfo(instId, mchntNo, termNo);
        /* Step 1 ：获取终端主密钥*/
        TermKeyMapper termKeyMapper = new TermKeyMapperImpl();
        TermKey tmkTermkey = termKeyMapper.getTermKey(instId, mchntNo, termNo, KeyTypeEnum.TMK.getTypeCode());
        /*判断终端主密钥是否存在*/
        if (tmkTermkey == null || StringUtil.isEmptyOrNull(tmkTermkey.getKeyValue())) {
            rglog.error("終端未下载终端主秘钥，请先下载主秘钥");
            bizResponse.setRespCode(RespCodeEnum.TERM_TMK_NOT_DOWNLOAD.getRespCode());
            bizResponse.setRespDesc(RespCodeEnum.TERM_TMK_NOT_DOWNLOAD.getRespDesc());
            return bizResponse;
        }
        SysParamService sysParamService = new SysParamServiceImpl();
        /*根据参数类型和参数键值查询参数信息*/
        SysParam sysParam = sysParamService.getSysParamInfo(instId, McpsParamConstant.MCPS_SYS_ID, McpsParamConstant.ALG_TYPE);
        if (null == sysParam) {
            rglog.error("算法查询为空！instId:<{}>,type:<{}>,key:<{}>", posSignInRequest.getHeader().getInstId(),
                    McpsParamConstant.MCPS_SYS_ID, McpsParamConstant.ALG_TYPE);
            throw new BizException(RespCodeEnum.CERT_INFO_NOT_EXIST.getRespCode(), "算法查询为空");
        }
        String algorithmType = sysParam.getParamValue();


        String[] value = tmkTermkey.getKeyValue().split("\\|");

        List<TermWorkKeyInfo> termWorkKeyInfoList = null;
        if ("3DES".equals(algorithmType)) {
            termWorkKeyInfoList = gen3DESWorkKey(value[0]);
        } else if ("SM4".equals(algorithmType)) {
            termWorkKeyInfoList = genSm4WorkKey(value[0]);
        }

        /* 下发批次号 */
        String sBatchNo = "000001";
        if (mchntTermInfo.getBatchNo() != null) {
            sBatchNo = mchntTermInfo.getBatchNo();
        } else {
            mchntTermInfo.setBatchNo(sBatchNo);
        }
        /* 更新终端状态 与终端密钥信息表不在一个库中，所以无法再一个事务中处理 */
        mchntTermInfo.setTermSignStatus("1");
        boolean updateFlag = mchntService.updateMchntTermInfo("01", mchntTermInfo);
        if (!updateFlag) {
            rglog.error("更新终端状态失败");
            throw new BizException(RespCodeEnum.UPDATE_TERM_INFO_ERROR.getRespCode(), RespCodeEnum.UPDATE_TERM_INFO_ERROR.getRespDesc());
        }


        /* 重组响应结果 */
        PosSignInResponse posSignInResponse = new PosSignInResponse();
        ConvertUtil.convertOutput(posSignInResponse);
        posSignInResponse.setTermWorkKeyInfoList(termWorkKeyInfoList);
        posSignInResponse.setBatchNo(sBatchNo);
        posSignInResponse.setTxnDate(DateUtil.getCurrentDate());
        posSignInResponse.setTxnTime(DateUtil.getCurrentTime());
        posSignInResponse.setParamDownFlag("000"); //签到默认需要下载参数
        bizResponse.setRspSysId(AppParamConstant.SYS_ID);
        bizResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
        bizResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        bizResponse.setResult(posSignInResponse);
        return bizResponse;
    }

    @Override
    protected void bizAfterCust(Object response) throws Exception {
        BizResponse bizResponse = (BizResponse) response;
        PosSignInResponse posSignInResponse = (PosSignInResponse) bizResponse.getResult();
        ConvertUtil.convertInput(posSignInResponse);
    }


    List<TermWorkKeyInfo> gen3DESWorkKey(String tmkKey) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        List<TermWorkKeyInfo> termWorkKeyInfoList = new ArrayList<>();
        TermWorkKeyInfo termWorkKeyInfo = new TermWorkKeyInfo();
        /*随机生成签名验签密钥*/
        String takKey = SM4Util.generateSm4Key(128);
        String takCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(DES3Util.genCheckValue(ByteUtil.hexStringToByte(takKey)))).substring(0, 8);
        String encTakKey = ByteUtil.bytesToHexString(DES3Util.encryptMode3DESDouble(ByteUtil.hexStringToByte(tmkKey), ByteUtil.hexStringToByte(takKey)));
        termWorkKeyInfo.setCheckValue(takCheckValue);
        termWorkKeyInfo.setKeyValue(encTakKey);
        termWorkKeyInfo.setKeyType(KeyTypeEnum.TAK.getTypeCode());
        termWorkKeyInfoList.add(termWorkKeyInfo);
        /*随机生成pin密钥*/
        String tpkKey = SM4Util.generateSm4Key(128);
        String tpkCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(DES3Util.genCheckValue(ByteUtil.hexStringToByte(tpkKey)))).substring(0, 8);
        String encTpkKey = ByteUtil.bytesToHexString(DES3Util.encryptMode3DESDouble(ByteUtil.hexStringToByte(tmkKey), ByteUtil.hexStringToByte(tpkKey)));
        termWorkKeyInfo.setCheckValue(tpkCheckValue);
        termWorkKeyInfo.setKeyValue(encTpkKey);
        termWorkKeyInfo.setKeyType(KeyTypeEnum.TPK.getTypeCode());
        termWorkKeyInfoList.add(termWorkKeyInfo);
        /*随机生成pin密钥*/
        String tdkKey = SM4Util.generateSm4Key(128);
        String tdkCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(DES3Util.genCheckValue(ByteUtil.hexStringToByte(tdkKey)))).substring(0, 8);
        String encTdkKey = ByteUtil.bytesToHexString(DES3Util.encryptMode3DESDouble(ByteUtil.hexStringToByte(tmkKey), ByteUtil.hexStringToByte(tdkKey)));
        termWorkKeyInfo.setCheckValue(tdkCheckValue);
        termWorkKeyInfo.setKeyValue(encTdkKey);
        termWorkKeyInfo.setKeyType(KeyTypeEnum.TDK.getTypeCode());
        termWorkKeyInfoList.add(termWorkKeyInfo);
        /* 开启数据库事务 */
        String dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.DATABASE_CONF_NODE, AppConfigConstant.OLTP_POOL_NAME);
        String corporation = xmlTreeUtil.getXmlTreeStringValue(AppParamConstant.CORPORATION);
        if (null != corporation && !corporation.isEmpty()) {
            String dbPoolCashNode = corporation.trim() + AppParamConstant.DATABASE_CONF_NODE;
            dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(dbPoolCashNode, AppConfigConstant.OLTP_POOL_NAME);
        }
        DbsUtil dbsUtil = new DbsUtil(dbPoolName);
        dbsUtil.dbsBeginTransaction();

        TermKey termWorkKey = new TermKey();
        ConvertUtil.convertOutput(termWorkKey);
        /*插入签名密钥*/
        termWorkKey.setAlgorithmType("3DES");
        termWorkKey.setKeyType(KeyTypeEnum.TAK.getTypeCode());
        termWorkKey.setKeyValue(takKey);
        termWorkKey.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"));
        termWorkKey.setKeyStatus("1");
        termWorkKey.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"));
        insertTermKey(dbsUtil, termWorkKey);
        /*插入pin密钥*/
        termWorkKey.setKeyType(KeyTypeEnum.TPK.getTypeCode());
        termWorkKey.setKeyValue(tpkKey);
        insertTermKey(dbsUtil, termWorkKey);
        /*插入tdp密钥*/
        termWorkKey.setKeyType(KeyTypeEnum.TDK.getTypeCode());
        termWorkKey.setKeyValue(tdkKey);
        insertTermKey(dbsUtil, termWorkKey);

        /* 结束数据库事务 */
        dbsUtil.dbsEndTransaction(true);

        return termWorkKeyInfoList;
    }

    List<TermWorkKeyInfo> genSm4WorkKey(String tmkKey) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        List<TermWorkKeyInfo> termWorkKeyInfoList = new ArrayList<>();
        TermWorkKeyInfo termWorkKeyInfo = new TermWorkKeyInfo();
        byte[] bEncTakKey = new byte[16];
        byte[] bEncTpkKey = new byte[16];
        byte[] bEncTdkKey = new byte[16];
        /*随机生成签名验签密钥*/
        String takKey = SM4Util.generateSm4Key(128);
        String takCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(SM4Util.genCheckValue(ByteUtil.hexStringToByte(takKey)))).substring(0, 16);
        int iRetCode = SM4Util.sms4(ByteUtil.hexStringToByte(takKey), ByteUtil.hexStringToByte(takKey).length, ByteUtil.hexStringToByte(tmkKey), bEncTakKey, SM4Util.ENCRYPT);
        if (iRetCode != 0) {
            rglog.error("Sm4主密钥加密工作密钥失败");
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
        String encTakKey = ByteUtil.bytesToHexString(bEncTakKey);
        termWorkKeyInfo.setCheckValue(takCheckValue);
        termWorkKeyInfo.setKeyValue(encTakKey);
        termWorkKeyInfo.setKeyType(KeyTypeEnum.TAK.getTypeCode());
        termWorkKeyInfoList.add(termWorkKeyInfo);
        /*随机生成pin密钥*/
        String tpkKey = SM4Util.generateSm4Key(128);
        String tpkCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(SM4Util.genCheckValue(ByteUtil.hexStringToByte(tpkKey)))).substring(0, 16);
        iRetCode = SM4Util.sms4(ByteUtil.hexStringToByte(tpkKey), ByteUtil.hexStringToByte(tpkKey).length, ByteUtil.hexStringToByte(tmkKey), bEncTpkKey, SM4Util.ENCRYPT);
        if (iRetCode != 0) {
            rglog.error("Sm4主密钥加密工作密钥失败");
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
        String encTpkKey = ByteUtil.bytesToHexString(bEncTpkKey);
        TermWorkKeyInfo termPinWorkKeyInfo = new TermWorkKeyInfo();
        termPinWorkKeyInfo.setCheckValue(tpkCheckValue);
        termPinWorkKeyInfo.setKeyValue(encTpkKey);
        termPinWorkKeyInfo.setKeyType(KeyTypeEnum.TPK.getTypeCode());
        termWorkKeyInfoList.add(termPinWorkKeyInfo);
        /*随机生成tdp密钥*/
        String tdkKey = SM4Util.generateSm4Key(128);
        String tdkCheckValue = Objects.requireNonNull(ByteUtil.bytesToHexString(SM4Util.genCheckValue(ByteUtil.hexStringToByte(tdkKey)))).substring(0, 16);
        iRetCode = SM4Util.sms4(ByteUtil.hexStringToByte(tdkKey), ByteUtil.hexStringToByte(tdkKey).length, ByteUtil.hexStringToByte(tmkKey), bEncTdkKey, SM4Util.ENCRYPT);
        if (iRetCode != 0) {
            rglog.error("Sm4主密钥加密工作密钥失败");
            throw new BizException(RespCodeEnum.SYSTEM_ERROR.getRespCode(), RespCodeEnum.SYSTEM_ERROR.getRespDesc());
        }
        String encTdkKey = ByteUtil.bytesToHexString(bEncTdkKey);
        TermWorkKeyInfo termTdkWorkKeyInfo = new TermWorkKeyInfo();
        termTdkWorkKeyInfo.setCheckValue(tdkCheckValue);
        termTdkWorkKeyInfo.setKeyValue(encTdkKey);
        termTdkWorkKeyInfo.setKeyType(KeyTypeEnum.TDK.getTypeCode());
        termWorkKeyInfoList.add(termTdkWorkKeyInfo);
        /* 开启数据库事务 */
        String dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.DATABASE_CONF_NODE, AppConfigConstant.OLTP_POOL_NAME);
        String corporation = xmlTreeUtil.getXmlTreeStringValue(AppParamConstant.CORPORATION);
        if (null != corporation && !corporation.isEmpty()) {
            String dbPoolCashNode = corporation.trim() + AppParamConstant.DATABASE_CONF_NODE;
            dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(dbPoolCashNode, AppConfigConstant.OLTP_POOL_NAME);
        }
        DbsUtil dbsUtil = new DbsUtil(dbPoolName);
        dbsUtil.dbsBeginTransaction();

        TermKey termWorkKey = new TermKey();
        ConvertUtil.convertOutput(termWorkKey);
        /*插入签名密钥*/
        termWorkKey.setAlgorithmType("SM4");
        termWorkKey.setKeyType(KeyTypeEnum.TAK.getTypeCode());
        termWorkKey.setKeyValue(takKey);
        termWorkKey.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"));
        termWorkKey.setKeyStatus("1");
        termWorkKey.setUpdateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss"));
        termWorkKey.setKeyDesc("签名密钥");
        insertTermKey(dbsUtil, termWorkKey);
        /*插入pin密钥*/
        termWorkKey.setKeyType(KeyTypeEnum.TPK.getTypeCode());
        termWorkKey.setKeyValue(tpkKey);
        termWorkKey.setKeyDesc("pin密钥");
        insertTermKey(dbsUtil, termWorkKey);
        /*插入tdp密钥*/
        termWorkKey.setKeyType(KeyTypeEnum.TDK.getTypeCode());
        termWorkKey.setKeyValue(tdkKey);
        termWorkKey.setKeyDesc("敏感信息密钥");
        insertTermKey(dbsUtil, termWorkKey);

        /* 结束数据库事务 */
        dbsUtil.dbsEndTransaction(true);

        return termWorkKeyInfoList;
    }

    void insertTermKey(DbsUtil dbsUtil, TermKey termKey) throws Exception {
        int iRetCode;
        TermKeyMapper termKeyMapper = new TermKeyMapperImpl();
        TermKey termKeyTmp = termKeyMapper.getTermKey(termKey.getInstId(), termKey.getMchntNo(), termKey.getTermNo(), termKey.getKeyType());
        if (termKeyTmp == null) {
            rglog.error("未获取到签名密钥，插入密钥");
            iRetCode = termKeyMapper.insertTermKeyTransaction(termKey);
        } else {
            /*更新主密钥*/
            termKeyTmp.setKeyValue(termKey.getKeyValue());
            termKeyTmp.setUpdateTime(termKey.getUpdateTime());
            iRetCode = termKeyMapper.updateTermKeyByPkTransaction(termKeyTmp);
        }
        if (iRetCode != 0) {
            rglog.error("更新终端工作密钥失败，retCode<{}>", iRetCode);
            dbsUtil.dbsEndTransaction(false);
            throw new BizException(RespCodeEnum.UPDATE_TERM_KEY_ERROR.getRespCode(), RespCodeEnum.UPDATE_TERM_KEY_ERROR.getRespDesc());
        }
    }
}
